<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<script>

  /**
   * Define property metadata.
   *
   *     properties: {
   *       <property>: <Type || Object>,
   *       ...
   *     }
   *
   * Example:
   *
   *     properties: {
   *       // `foo` property can be assigned via attribute, will be deserialized to
   *       // the specified data-type. All `properties` properties have this behavior.
   *       foo: String,
   *
   *       // `bar` property has additional behavior specifiers.
   *       //   type: as above, type for (de-)serialization
   *       //   notify: true to send a signal when a value is set to this property
   *       //   reflectToAttribute: true to serialize the property to an attribute
   *       //   readOnly: if true, the property has no setter
   *       bar: {
   *         type: Boolean,
   *         notify: true
   *       }
   *     }
   *
   * By itself the properties feature doesn't do anything but provide property
   * information. Other features use this information to control behavior.
   *
   * The `type` information is used by the `attributes` feature to convert
   * String values in attributes to typed properties. The `bind` feature uses
   * property information to control property access.
   *
   * Marking a property as `notify` causes a change in the property to
   * fire a non-bubbling event called `<property>-changed`. Elements that
   * have enabled two-way binding to the property use this event to
   * observe changes.
   *
   * `readOnly` properties have a getter, but no setter. To set a read-only
   * property, use the private setter method `_set_<property>(value)`.
   *
   * @class base feature: properties
   */

  // null object
  Polymer.nob = Object.create(null);

  Polymer.Base._addFeature({

    /**
     * Returns a property descriptor object for the property specified.
     *
     * This method allows introspecting the configuration of a Polymer element's
     * properties as configured in its `properties` object.  Note, this method
     * normalizes shorthand forms of the `properties` object into longhand form.
     *
     * @method getPropertyInfo
     * @param {string} property Name of property to introspect.
     * @return {Object} Property descriptor for specified property.
    */
    // TODO(sorvell): This function returns the first property object found
    // and this is not the property info Polymer acts on for readOnly or type
    // This api should be combined with _propertyInfo.
    getPropertyInfo: function(property) {
      var info = this._getPropertyInfo(property, this.properties);
      if (!info) {
        for (var i=0; i < this.behaviors.length; i++) {
          info = this._getPropertyInfo(property, this.behaviors[i].properties);
          if (info) {
            return info;
          }
        }
      }
      return info || Polymer.nob;
    },

    _getPropertyInfo: function(property, properties) {
      var p = properties && properties[property];
      if (typeof(p) === 'function') {
        p = properties[property] = {
          type: p
        };
      }
      // Let users determine whether property was defined without null check
      if (p) {
        p.defined = true;
      }
      return p;
    },

    // union properties, behaviors.properties, and propertyEffects
    _prepPropertyInfo: function() {
      this._propertyInfo = {};
      for (var i=0; i < this.behaviors.length; i++) {
        this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
      }
      this._addPropertyInfo(this._propertyInfo, this.properties);
      this._addPropertyInfo(this._propertyInfo, this._propertyEffects);
    },

    // list of propertyInfo with {readOnly, type, attribute}
    _addPropertyInfo: function(target, source) {
      if (source) {
        var t, s;
        for (var i in source) {
          t = target[i];
          s = source[i];
          // optimization: avoid info'ing properties that are protected and
          // not read only since they are not needed for attributes or
          // configuration.
          if (i[0] === '_' && !s.readOnly) {
            continue;
          }
          if (!target[i]) {
            target[i] = {
              type: typeof(s) === 'function' ? s : s.type,
              readOnly: s.readOnly,
              attribute: Polymer.CaseMap.camelToDashCase(i)
            }
          } else {
            if (!t.type) {
              t.type = s.type;
            }
            if (!t.readOnly) {
              t.readOnly = s.readOnly;
            }
          }
        }
      }
    }

  });

/*
 * Object containing property configuration data, where keys are property
 * names and values are descriptor objects that configure Polymer features
 * for the property.  Valid fields in the property descriptor object are
 * as follows:
 *
 * * `type` - used to determine how to deserialize attribute value strings
 *    to JS properties.  By convention, this field takes a JS constructor
 *    for the type, such as `String` or `Boolean`.
 * * `value` - default value for the property.  The value may either be a
 *    primitive value, or a function that returns a value (which should be
 *    used for initializing Objects and Arrays to avoid shared objects on
 *    instances).
 * * `notify` - when `true`, configures the property to fire a non-bubbling
 *    event called `<property>-changed` for each change to the property.
 *    Elements that have enabled two-way binding to the property use this
 *    event to observe changes.
 * * `readOnly` - when `true` configures the property to have a getter, but
 *    no setter. To set a read-only property, use the private setter method
 *    `_set_<property>(value)`.
 * * `reflectToAttribute` - when `true` configures the property value to
 *    be serialized to a string and reflected to the attribute each time
 *    it changes.  This can impact performance, so it should be used
 *    only when reflecting the attribute value is important.
 * * `observer` - indicates the name of a function that should be called
 *    each time the property changes. `e.g.: `observer: 'valueChanged'
 * * `computed` - configures the property to be computed by a computing
 *    function each time one or more dependent properties change.
 *    `e.g.: `computed: 'computeValue(prop1, prop2)'
 *
 * Note: a shorthand may be used for the object descriptor when only the
 * type needs to be specified by using the type as the descriptor directly.
 * @memberof! feature: properties
 */
(function() {
  var propertiesDesc = {configurable: true, writable: true, enumerable: true,
    value: {}};
  Polymer.BaseDescriptors.properties = propertiesDesc;
  Object.defineProperty(Polymer.Base, 'properties', propertiesDesc);
})();

</script>
